package com.cskaoyan.market.service;

import com.cskaoyan.market.db.domain.*;
import com.cskaoyan.market.db.mapper.*;
import com.cskaoyan.market.util.MybatisUtils;
import com.cskaoyan.market.vo.GoodsDetailMarketBrandVo;
import com.cskaoyan.market.vo.MarketGoodsDetailCategoryVo;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AdminGoodsServiceImpl implements AdminGoodsService {
    //通过字符串检校解决sql注入问题返回true表示字符串存在sql注入
    public static boolean containsSqlInjection(Object obj) {
        Pattern pattern = Pattern.compile(
                "\\b(and|exec|insert|select|drop|grant|alter|delete|update|count|chr|mid|master|truncate|char|declare|or)\\b|(\\*|;|\\+|'|%)");
        Matcher matcher = pattern.matcher(obj.toString());
        return matcher.find();
    }

    @Override
    public List<MarketGoods> list(String page, String limit, String sort, String order, String goodsSn, String name, String goodsId) {
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsMapper marketGoodsMapper = session.getMapper(MarketGoodsMapper.class);
        MarketGoodsExample marketGoodsExample = new MarketGoodsExample();

        if (sort != null && containsSqlInjection(sort)) {
            return null;
        }
        if (order != null && containsSqlInjection(order)) {
            return null;
        }
        MarketGoodsExample.Criteria criteria = marketGoodsExample.createCriteria();
        if (!StringUtils.isEmpty(goodsId)) {
            criteria.andIdEqualTo(Integer.valueOf(goodsId));
        }
        if (!StringUtils.isEmpty(goodsSn)) {
            criteria.andGoodsSnLike("%" + goodsSn + "%");
        }
        if (!StringUtils.isEmpty(name)) {
            criteria.andNameLike("%" + name + "%");
        }
        marketGoodsExample.setOrderByClause(sort + " " + order);
        PageHelper.startPage(Integer.parseInt(page), Integer.parseInt(limit));
        List<MarketGoods> marketGoods = marketGoodsMapper.selectByExample(marketGoodsExample);
        session.close();
        return marketGoods;
    }

    @Override
    public Map<String, Object> detail(String goodsId, String sort, String order) {
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsMapper mapper = session.getMapper(MarketGoodsMapper.class);

        MarketGoodsExample marketGoodsExample = new MarketGoodsExample();
        MarketGoodsExample.Criteria criteria = marketGoodsExample.createCriteria();
        criteria.andIdEqualTo(Integer.parseInt(goodsId));
        if (sort != null && containsSqlInjection(sort)) {
            return null;
        }
        if (order != null && containsSqlInjection(order)) {
            return null;
        }
        MarketGoods marketGoods = mapper.selectOneByExample(marketGoodsExample);
        Map<String, Object> data = new HashMap<>();
        Integer categoryId = marketGoods.getCategoryId();
        Deque<Integer> categoryIds = new ArrayDeque<>();

        while (categoryId != null) {
            if (categoryId != 0) {
                categoryIds.push(categoryId);
            }
            categoryId = selectCategoryPidById(categoryId);
        }

        data.put("categoryIds", categoryIds);
        data.put("goods", marketGoods);
        List<MarketGoodsAttribute> attributes = getArrtibutesByGoodsId(marketGoods.getId());
        data.put("attributes", attributes);

        List<MarketGoodsSpecification> specifications = getSpecificationsByGoodsId(marketGoods.getId());
        data.put("specifications", specifications);
        List<MarketGoodsProduct> products = getProductsByGoodsId(marketGoods.getId());
        data.put("products", products);
        return data;
    }

    @Override
    public List<MarketGoodsDetailCategoryVo> categoryList() {
        SqlSession session = MybatisUtils.getSession();
        MarketCategoryMapper categoryMapper = session.getMapper(MarketCategoryMapper.class);
        List<MarketCategory> marketCategories = categoryMapper.selectByExample(new MarketCategoryExample());
        session.close();

        Map<Integer, List<MarketCategory>> data = groupByPid(marketCategories);
        List<MarketGoodsDetailCategoryVo> vos=new ArrayList<>();
        List<MarketCategory> levelOne=data.get(0);
        for (MarketCategory marketCategory : levelOne) {
            List<MarketGoodsDetailCategoryVo> levelTwo=new ArrayList<>();
            //第一级类别的实体，此时它的二级类别列表为空
            MarketGoodsDetailCategoryVo marketGoodsDetailCategoryVo=
                    new MarketGoodsDetailCategoryVo(marketCategory.getId(),marketCategory.getName(),levelTwo);
            //一级类别加入结果集
            vos.add(marketGoodsDetailCategoryVo);
            //一级类别的二级类别列表
            List<MarketCategory> marketCategories1 = data.get(marketCategory.getId());
            for (MarketCategory category : marketCategories1) {
                MarketGoodsDetailCategoryVo marketGoodsDetailCategoryVoLevelTwo=
                        new MarketGoodsDetailCategoryVo(category.getId(),category.getName(),null);
                //填充当前一级下的二级类别列表
                levelTwo.add(marketGoodsDetailCategoryVoLevelTwo);
            }
        }

        return vos;
    }

    @Override
    public List<GoodsDetailMarketBrandVo> brandList() {
        SqlSession session=MybatisUtils.getSession();
        MarketBrandMapper mapper = session.getMapper(MarketBrandMapper.class);
        MarketBrandExample marketBrandExample = new MarketBrandExample();
        List<MarketBrand> marketBrandList = mapper.selectByExample(marketBrandExample);
        List<GoodsDetailMarketBrandVo> vos =new ArrayList<>();
        for (MarketBrand marketBrand : marketBrandList) {
            GoodsDetailMarketBrandVo goodsDetailMarketBrandVo = new GoodsDetailMarketBrandVo(marketBrand.getId(), marketBrand.getName());
            vos.add(goodsDetailMarketBrandVo);
        }
        return vos;
    }

    @Override
    public boolean updateGoods(MarketGoods goods, List<MarketGoodsAttribute> attributes, List<MarketGoodsProduct> products, List<MarketGoodsSpecification> specifications) {
        boolean flag=false;
        SqlSession session=MybatisUtils.getSession();
        try {
            MarketGoodsMapper mapper = session.getMapper(MarketGoodsMapper.class);
            LocalDateTime now = LocalDateTime.now();
            goods.setUpdateTime(now);
            int i = mapper.updateByPrimaryKey(goods);



            if (i!=0)flag=true;
            MarketGoodsSpecificationMapper mapper1 = session.getMapper(MarketGoodsSpecificationMapper.class);

            for (MarketGoodsSpecification specification : specifications) {
                MarketGoodsSpecification sp = new MarketGoodsSpecification();
                sp.setId(specification.getId());
                sp.setPicUrl(specification.getPicUrl());
                sp.setUpdateTime(now);
                i = mapper1.updateByPrimaryKeySelective(sp);
                if (i!=0)flag=true;
            }
            MarketGoodsProductMapper mapper2 = session.getMapper(MarketGoodsProductMapper.class);
            for (MarketGoodsProduct product : products) {
                MarketGoodsProduct marketGoodsProduct = new MarketGoodsProduct();
                marketGoodsProduct.setId(product.getId());
                marketGoodsProduct.setPrice(product.getPrice());
                marketGoodsProduct.setNumber(product.getNumber());
                marketGoodsProduct.setUrl(product.getUrl());
                marketGoodsProduct.setUpdateTime(now);
                i = mapper2.updateByPrimaryKeySelective(marketGoodsProduct);
                if(i!=0)flag=true;
            }
            MarketGoodsAttributeMapper mapper3 = session.getMapper(MarketGoodsAttributeMapper.class);
            for (MarketGoodsAttribute attribute : attributes) {

                if (i!=0)flag=true;
                if (attribute.getId()==null){
                    attribute.setGoodsId(goods.getId());
                    attribute.setAddTime(now);
                    attribute.setUpdateTime(now);
                    i=mapper3.insert(attribute);
                    continue;
                }
                if (attribute.getDeleted()!=null&&attribute.getDeleted()==true){
                    i=mapper3.deleteByPrimaryKey(attribute.getId());
                    continue;
                }
                attribute.setUpdateTime(now);
                mapper3.updateByPrimaryKey(attribute);
            }
            if (i!=0)flag=true;
            session.commit();
        }catch (Exception e){
            session.rollback();
            e.printStackTrace();
        }finally {
            session.close();
        }
        return flag;
    }

    @Override
    public int delete(Integer id) {

        SqlSession session=MybatisUtils.getSession();
        MarketGoodsMapper mapper = session.getMapper(MarketGoodsMapper.class);
        mapper.deleteByPrimaryKey(id);

        MarketGoodsAttributeMapper mapper1 = session.getMapper(MarketGoodsAttributeMapper.class);
        MarketGoodsAttributeExample marketGoodsAttributeExample = new MarketGoodsAttributeExample();
        MarketGoodsAttributeExample.Criteria criteria = marketGoodsAttributeExample.createCriteria();
        criteria.andGoodsIdEqualTo(id);
        int i = mapper1.deleteByExample(marketGoodsAttributeExample);

        MarketGoodsProductMapper mapper2 = session.getMapper(MarketGoodsProductMapper.class);
        MarketGoodsProductExample marketGoodsProductExample = new MarketGoodsProductExample();
        MarketGoodsProductExample.Criteria criteria1 = marketGoodsProductExample.createCriteria();
        criteria1.andGoodsIdEqualTo(id);
        int i1 = mapper2.deleteByExample(marketGoodsProductExample);
        if (i==0)i=i1;

        MarketGoodsSpecificationMapper mapper3 = session.getMapper(MarketGoodsSpecificationMapper.class);
        MarketGoodsSpecificationExample marketGoodsSpecificationExample = new MarketGoodsSpecificationExample();
        MarketGoodsSpecificationExample.Criteria criteria2 = marketGoodsSpecificationExample.createCriteria();
        criteria2.andGoodsIdEqualTo(id);
        int i2 = mapper3.deleteByExample(marketGoodsSpecificationExample);
        if (i==0)i=i2;

        session.commit();
        session.close();
        return i;
    }

    private Map<Integer, List<MarketCategory>> groupByPid(List<MarketCategory> marketCategories) {
        Map<Integer, List<MarketCategory>> map = new HashMap<Integer, List<MarketCategory>>();
        for (MarketCategory category : marketCategories) {
            Integer pid = category.getPid();
            List<MarketCategory> list = map.get(pid);
            if(list == null){
                list = new ArrayList<>();
            }
            list.add(category);
            map.put(pid, list);
        }
        return map;
    }

    private List<MarketGoodsProduct> getProductsByGoodsId(Integer goodsId) {
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsProductMapper mapper = session.getMapper(MarketGoodsProductMapper.class);
        MarketGoodsProductExample marketGoodsProductExample = new MarketGoodsProductExample();
        MarketGoodsProductExample.Criteria criteria = marketGoodsProductExample.createCriteria();
        criteria.andGoodsIdEqualTo(goodsId);
        List<MarketGoodsProduct> products = mapper.selectByExample(marketGoodsProductExample);
        return products;
    }

    private List<MarketGoodsSpecification> getSpecificationsByGoodsId(Integer goodsId) {
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsSpecificationMapper mapper = session.getMapper(MarketGoodsSpecificationMapper.class);
        MarketGoodsSpecificationExample marketGoodsSpecificationExample = new MarketGoodsSpecificationExample();
        MarketGoodsSpecificationExample.Criteria criteria = marketGoodsSpecificationExample.createCriteria();
        criteria.andGoodsIdEqualTo(goodsId);
        List<MarketGoodsSpecification> specifications = mapper.selectByExample(marketGoodsSpecificationExample);
        return specifications;
    }

    private List<MarketGoodsAttribute> getArrtibutesByGoodsId(Integer goodsId) {
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsAttributeMapper mapper = session.getMapper(MarketGoodsAttributeMapper.class);
        MarketGoodsAttributeExample marketGoodsAttributeExample = new MarketGoodsAttributeExample();
        MarketGoodsAttributeExample.Criteria criteria = marketGoodsAttributeExample.createCriteria();
        criteria.andGoodsIdEqualTo(goodsId);
        List<MarketGoodsAttribute> attributes = mapper.selectByExample(marketGoodsAttributeExample);
        return attributes;
    }

    private Integer selectCategoryPidById(Integer categoryId) {
        SqlSession session = MybatisUtils.getSession();
        MarketCategoryMapper mapper = session.getMapper(MarketCategoryMapper.class);

        MarketCategoryExample marketCategoryExample = new MarketCategoryExample();
        MarketCategoryExample.Criteria criteria = marketCategoryExample.createCriteria();
        criteria.andIdEqualTo(categoryId);
        MarketCategory marketCategory = mapper.selectOneByExample(marketCategoryExample);
        if (marketCategory == null) return null;
        return marketCategory.getPid();
    }

    @Override
    public void insert(MarketGoods goods, List<MarketGoodsSpecification> specifications, List<MarketGoodsAttribute> attributes, List<MarketGoodsProduct> products) {
        //首先给goods赋值，还有一些属性没有值，retailPrice  时间  deleted(如果是物理删除，那么不用理会该字段)
        //应该获取位于products里面较低的价格，赋值给retailPrice
        BigDecimal retailPrice = products.get(0).getPrice();
        for (int i = 0; i < products.size(); i++) {
            MarketGoodsProduct product = products.get(i);
            //遍历，如果出现了一个更小的价格，那么把更小的价格赋值给retailPrice
            // -1 小于 0 等于 1  大于
            if (product.getPrice().compareTo(retailPrice) == -1) {
                retailPrice = product.getPrice();
            }
        }

        goods.setRetailPrice(retailPrice);
        goods.setAddTime(LocalDateTime.now());
        goods.setUpdateTime(LocalDateTime.now());
        goods.setDeleted(false);
        SqlSession session = MybatisUtils.getSession();
        MarketGoodsMapper marketGoodsMapper = session.getMapper(MarketGoodsMapper.class);
        MarketGoodsSpecificationMapper specificationMapper = session.getMapper(MarketGoodsSpecificationMapper.class);
        MarketGoodsProductMapper productMapper = session.getMapper(MarketGoodsProductMapper.class);
        MarketGoodsAttributeMapper attributeMapper = session.getMapper(MarketGoodsAttributeMapper.class);
        // insert into (xx,xx) values (xx,xx)---除了这两列之外的其他列，如果有默认值，则会赋值默认值
        // insert into xxx values (xx,xx,xx,xx,xx,xx)---给全部的列赋值，但是实体类里面有很多的null，所以这一列会被赋值null
        try {
            marketGoodsMapper.insert(goods);
            Integer goodsId = goods.getId();
            //关于下面这三个插入，大家可以自定义一个插入方法，使用foreach标签来进行
            for (MarketGoodsSpecification sp : specifications) {
                sp.setGoodsId(goodsId);
                sp.setAddTime(LocalDateTime.now());
                sp.setUpdateTime(LocalDateTime.now());
                specificationMapper.insert(sp);
            }
            for (MarketGoodsAttribute attribute : attributes) {
                attribute.setGoodsId(goodsId);
                attribute.setAddTime(LocalDateTime.now());
                attribute.setUpdateTime(LocalDateTime.now());
                attributeMapper.insert(attribute);
            }

            for (MarketGoodsProduct product : products) {
                product.setAddTime(LocalDateTime.now());
                product.setUpdateTime(LocalDateTime.now());
                product.setGoodsId(goodsId);
                productMapper.insert(product);
            }
            session.commit();
        } catch (Exception e) {
            session.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}
